/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_zml.htm
 *
 * Zhiqim Zml is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.zml.expression.operator;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Maps;
import org.zhiqim.kernel.util.Types;
import org.zhiqim.zml.Expression;
import org.zhiqim.zml.ExpressionParser;
import org.zhiqim.zml.ZmlVariable;
import org.zhiqim.zml.exception.ExpressionException;
import org.zhiqim.zml.exception.PropertNotExistException;
import org.zhiqim.zml.expression.Operator;
import org.zhiqim.zml.expression.primitive._Variable;

/**
 * 可索引表达式，对应方括号[]：
 * 1、数组下标，如array[0]
 * 2、列表坐标、如list[0]
 * 3、MAP取值、如map["key"]
 * 4、对象属性，如object["name"]
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class _Indexable extends Operator
{
    private Expression obj;//数组、列表、MAP等
    private Expression key;//键值
    
    private transient ArrayList<Expression> eList;
    
    public _Indexable()
    {
        this.eList = new ArrayList<Expression>(1);
    }
    
    @Override
    public int getType()
    {
        return INDEXABLE;
    }
    
    @Override
    public Object build(ZmlVariable variableMap) throws ExpressionException
    {
        Object target = obj.build(variableMap);
        Object tk = key.build(variableMap);
        if (target == null && tk == null)
            throw new ExpressionException("可索引表达式{"+this+"}，目标对象和键对象不能都为null");
        
        if (target == null)
        {//转到静态属性处理
            if (obj instanceof _Variable && tk instanceof String)
            {
                Class<?> clazz = ((_Variable)obj).buildClass();
                if (clazz == null)
                    throw new ExpressionException("属性表达式{"+this+"}，目标对象不能为null");
                
                try
                {
                    return new _Property(clazz, (String)tk).build(variableMap);
                }
                catch(PropertNotExistException e)
                {
                    //属性未找到不返回值
                }
            }
            
            throw new ExpressionException("可索引表达式{"+this+"}，目标对象或键对象不正确");
        }
        
        if (tk == null)
        {//转到MAP处理，MAP支持null键
            if (target instanceof Map)
            {//MAP类型
                return Maps.get(target, tk);
            }
            
            throw new ExpressionException("可索引表达式{"+this+"}，目标对象或键对象不正确");
        }

        //目标对象和键都不为null
        return buildIndexable(variableMap, target, tk);
    }
    
    /**
     * 生成可索引对象
     * 
     * @param variableMap           变量表
     * @param target                目标对象
     * @param tk                    键对象
     * @return                      索引后对象
     * @throws ExpressionException  异常
     */
    private Object buildIndexable(ZmlVariable variableMap, Object target, Object tk) throws ExpressionException
    {
        if (target.getClass().isArray())
        {//数组类型
            if (!Types.isInteger(tk) && !Types.isIntArray(tk))
                throw new ExpressionException("属性表达式{"+this+"}，格式不正确，数组要求键值为整型");
            
            Object[] ts = Arrays.toArray(target);
            if (Types.isInteger(tk))
            {
                int index = ((Number)tk).intValue();
                return ts[index];
            }
            else
            {
                int[] indexs = (int[])tk;
                if (indexs.length < 2)
                    return null;
                
                Object[] ds = new Object[indexs[indexs.length-1] - indexs[0]];
                for (int i=indexs[0];i<indexs[indexs.length-1];i++)
                {
                    ds[indexs[0] - i] = ts[indexs[0]];
                }
                return ds;
            }
        }
        else if (target instanceof String)
        {//字符串
            if (!Types.isInteger(tk) && !Types.isIntArray(tk))
                throw new ExpressionException("属性表达式{"+this+"}，格式不正确，数组要求键值为整型");
            
            String str = (String)target;
            if (Types.isInteger(tk))
            {
                int index = ((Number)tk).intValue();
                return str.charAt(index);
            }
            else
            {
                int[] indexs = (int[])tk;
                if (indexs.length < 2)
                    return null;
                
                return str.substring(indexs[0], indexs[indexs.length-1]);
            }
        }
        else if (target instanceof List)
        {//列表类型
            if (!Types.isInteger(tk) && !Types.isIntArray(tk))
                throw new ExpressionException("属性表达式{"+this+"}，格式不正确，数组要求键值为整型");
            
            List<?> list = (List<?>)target;
            if (Types.isInteger(tk))
            {
                int index = ((Number)tk).intValue();
                return list.get(index);
            }
            else
            {
                int[] indexs = (int[])tk;
                if (indexs.length < 2)
                    return null;
                
                List<Object> list2 = new ArrayList<Object>(indexs[indexs.length-1] - indexs[0]);
                for (int i=indexs[0];i<indexs[indexs.length-1];i++)
                {
                    list2.add(list.get(i));
                }
                return list2;
            }
        }
        else if (target instanceof Map)
        {//MAP类型
            Map<?, ?> map = (Map<?, ?>)target;
            return map.get(tk);
        }
        else if (tk instanceof String)
        {//对象取属性
            try
            {
                return new _Property(target, (String)tk).build(variableMap);
            }
            catch (PropertNotExistException e)
            {
                //属性未找到不返回
            }
        }
        
        throw new ExpressionException("可索引表达式{"+this+"}，格式不正确，目标对象不是数组｜列表｜MAP");
    }
    
    @Override
    public String toString()
    {
        return new StringBuilder().append(obj).append("[").append(key).append("]").toString() ;
    }
    
    public void addExpression(Expression expression)
    {
        eList.add(expression);
    }
    
    public void setObject(Expression obj)
    {
        this.obj = obj;
    }
    
    public boolean hasObject()
    {
        return obj != null;
    }
    
    public void parseBracketSquare() throws ExpressionException
    {
        //左右括号去除
        eList.remove(0);
        eList.remove(eList.size()-1);
        
        ExpressionParser.parse_Operator(eList);
        
        if (eList.size() > 1)
            throw new ExpressionException("属性表达式存在无法处理的表达式");
        
        key = eList.get(0);
        eList.clear();eList = null;
    }
}
